package com.tengol.leetcode;

import com.alibaba.fastjson.JSON;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 15. 三数之和
 *
 * 给你一个包含 n 个整数的数组 nums，判断 nums 中是否存在三个元素 a，b，c ，使得 a + b + c = 0 ？请你找出所有满足条件且不重复的三元组。
 * 注意：答案中不可以包含重复的三元组。
 *
 * 示例：
 * 给定数组 nums = [-1, 0, 1, 2, -1, -4]，
 * 满足要求的三元组集合为：
 * [
 *  [-1, 0, 1],
 *  [-1, -1, 2]
 * ]
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/3sum
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 *
 * 【解题思考过程】
 * 1. 借助 HashSet/HashMap 可以使用两重 for 循环
 * 2. 如何去重？ 卡在这个点了，去重意味着什么？
 *
 * @author dongrui
 * @date 2020/6/4 12:16
 */
public class No15ThreeSum {
    public List<List<Integer>> threeSum(int[] nums) {
        // 判空
        if(nums == null || nums.length < 3){
            return new ArrayList<>();
        }
        Set<List<Integer>> resultSet = new HashSet<>();
        // 先排序
        Arrays.sort(nums);
        // 结果集
        Map<Integer,String> cMap = new HashMap();
        for (int i = 1; i < nums.length; i++) {
            cMap.put(nums[i-1],null);
            int a = nums[i];
            for (int j = i + 1; j < nums.length; j++) {
                int b = nums[j];
                int c = -(a + b);
                if (cMap.containsKey(c)) {
                    resultSet.add(Arrays.asList(c,a,b));
                }
            }
        }

        return new ArrayList<>(resultSet);
    }



    public static void main(String[] args) {
        No15ThreeSum threeSum = new No15ThreeSum();
        int[] case1 = {-1, 0, 1, 2, -1, -4};
        int[] case2 = {0,0,0,0};
        List<List<Integer>> lists = threeSum.threeSum(case2);
        System.out.println(JSON.toJSONString(lists));
    }


    /**
     * 夹逼快速版
     *
     * 18 ms	45.6 MB
     * @param nums
     * @return
     */
    private List<List<Integer>> squeezeFastSolution(int[] nums) {
        if (nums == null || nums.length <= 2) {
            return Collections.emptyList();
        }
        List<List<Integer>> result = new LinkedList<>();

        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
            // 加速1：c为非负数，就不能满足a+b+c=0了
            if (nums[i] > 0) {
                return result;
            }
            // 加速2：跳过计算过的数据，同时防止结果重复
            if (i != 0 && nums[i] == nums[i-1]) {
                continue;
            }
            int head = i + 1;
            int tail = nums.length - 1;
            while (head < tail) {
                int sum = -(nums[head] + nums[tail]);
                if (sum == nums[i]) {
                    result.add(Arrays.asList(nums[i], nums[head], nums[tail]));
                    // 加速3：跳过计算过的数据，同时防止结果重复
                    while (head < tail && nums[head] == nums[head+1]) {
                        head++;
                    }
                    while (head < tail && nums[tail] == nums[tail-1]) {
                        tail--;
                    }
                }
                if (sum <= nums[i]) {
                    tail--;
                } else {
                    head++;
                }
            }
        }

        return result;
    }

    /**
     * 夹逼法
     * 899 ms	45.9 MB
     */
    private List<List<Integer>> squeezeSolution(int[] nums) {
        if (nums == null || nums.length <= 2) {
            return Collections.emptyList();
        }
        Set<List<Integer>> result = new LinkedHashSet<>();

        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
            int head = i + 1;
            int tail = nums.length - 1;
            while (head < tail) {
                int sum = -(nums[head] + nums[tail]);
                if (sum == nums[i]) {
                    List<Integer> value = Arrays.asList(nums[i], nums[head], nums[tail]);
                    result.add(value);
                }
                if (sum <= nums[i]) {
                    tail--;
                } else {
                    head++;
                }
            }
        }

        return new ArrayList<>(result);
    }
}





















